// Copyright (c) Microsoft Corporation.  All rights reserved.
#pragma once

/*
View objects are created based on CScfElement tree.

    <content>  ---> CContentElement tree -> CContentView
    <menu>     ---> CMenuElement tree    -> CMenuView or CContextMenuView
    <dialog>   ---> CDialogElement tree  -> CDialogView

View objects are responsible for rendering contents and handling keyevents.

CContentViewBase
    CContentView
        CDialogView
    CMenuView
        CContextMenuView
*/

enum CONTENT_VIEW_TYPE
{
    UNKNOWN_VIEW,
    SCF_CONTENT_VIEW,
    SCF_DIALOG_VIEW,
    SCF_MENU_VIEW,
    SCF_CONTEXT_MENU_VIEW
};

#define CONTENT_VIEW_FLAG_SCROLLBAR     1
#define CONTENT_VIEW_FLAG_NOSCROLLBAR   2
#define CONTENT_VIEW_FLAG_LAYOUT_VALID  4

class CContentViewBase
{
public:
    CContentViewBase()
    : m_ViewType(UNKNOWN_VIEW), m_pScfContentBase(NULL), m_dwFlags(0),
      m_nContentHeight(0), m_nClientWidth(0), m_nClientHeight(0), m_nViewTopOffset(0)
    {}
    
    virtual ~CContentViewBase();

    HRESULT AddViewItem(CViewItem* pItem);

    virtual HRESULT Initialize(CScfContentBase *pScfContentBase) = 0;
    virtual VOID OnEnter() {}
    virtual HRESULT OnSize(HDC hDC, LONG nClientWidth, LONG nClientHeight);
    virtual HRESULT OnNCPaint(HDC hdc, int left, int top, int right, int bottom);
    virtual HRESULT OnPaint(HDC hdc, int left, int top, int right, int bottom);
    virtual HRESULT OnDeviceEvent(CDevice::DeviceEvent deviceEvent);
    virtual HRESULT OnUpdateData(CScfContentBase* pScfContent);
    
    virtual SIZE DrawChild(HDC hdc, int left, int top, int right, int bottom, int iChild, CViewItem* pChild);
    virtual VOID DrawScrollbar(HDC hdc, int left, int top, int right, int bottom);
    
    CONTENT_VIEW_TYPE GetViewType() const { return m_ViewType; }
    LONG GetContentHeight() const { return m_nContentHeight; }
    
    VOID InvalidateContentLayout() { ClearFlag(CONTENT_VIEW_FLAG_LAYOUT_VALID); }
    BOOL IsContentLayoutValid() { return IsFlagSet(CONTENT_VIEW_FLAG_LAYOUT_VALID); }
    
    VOID SetFlag(DWORD dwFlags)   { m_dwFlags |= dwFlags; }
    VOID ClearFlag(DWORD dwFlags) { m_dwFlags &= ~dwFlags; }
    BOOL IsFlagSet(DWORD dwFlags) { return (m_dwFlags & dwFlags) == dwFlags; }
    
protected:
    HRESULT _ClearViewItems();
    
protected:
    CScfContentBase* m_pScfContentBase;
    vector<CViewItem*> m_items;

    CONTENT_VIEW_TYPE m_ViewType;
    DWORD m_dwFlags;
    LONG m_nContentHeight;
    LONG m_nClientWidth;
    LONG m_nClientHeight;
    LONG m_nViewTopOffset;
};

class CContentView : public CContentViewBase
{
public:
    CContentView()
    {
        m_ViewType = SCF_CONTENT_VIEW;
    }

    virtual ~CContentView(){}

    virtual HRESULT Initialize(CScfContentBase *pScfContentBase);
    virtual HRESULT OnSize(HDC hDC, LONG nClientWidth, LONG nClientHeight);
    virtual HRESULT OnPaint(HDC hdc, int left, int top, int right, int bottom);
    virtual HRESULT OnDeviceEvent(CDevice::DeviceEvent DeviceEvent);

    virtual VOID OnEnter()
    {
        m_nViewTopOffset = 0;
    }
};

class CDialogView : public CContentView
{
public:
    CDialogView()
    : m_nCurrentBtn(0), m_nButtonWidth(0)
    {
        m_ViewType = SCF_DIALOG_VIEW;
    }
    
    virtual ~CDialogView() {}

    virtual HRESULT Initialize(CScfContentBase *pScfContentBase);
    virtual HRESULT OnSize(HDC hDC, LONG nClientWidth, LONG nClientHeight);
    virtual HRESULT OnPaint(HDC hdc, int left, int top, int right, int bottom);
    virtual HRESULT OnDeviceEvent(CDevice::DeviceEvent DeviceEvent);
    
    virtual VOID OnEnter()
    {
        __super::OnEnter();
        m_nCurrentBtn = 0;
    }

private:
    size_t m_nCurrentBtn;
    LONG m_nButtonWidth;
    CScfImgElement m_FakeImgElement;    // fake <img> element for imgid attribute
};

class CMenuView : public CContentViewBase
{
public:
    CMenuView()
    : m_nDefItem(0), m_nCurrentItem(0)
    {
        m_ViewType = SCF_MENU_VIEW;
    }
    
    virtual ~CMenuView() {}

    virtual HRESULT Initialize(CScfContentBase *pScfContentBase);
    virtual VOID OnEnter();
    virtual HRESULT OnSize(HDC hDC, LONG nClientWidth, LONG nClientHeight);
    virtual HRESULT OnDeviceEvent(CDevice::DeviceEvent DeviceEvent);
    
    virtual SIZE DrawChild(HDC hdc, int left, int top, int right, int bottom, int iChild, CViewItem* pChild);
    virtual VOID DrawScrollbar(HDC hdc, int left, int top, int right, int bottom);

protected:
    VOID _AdjustViewTopOffset();

    size_t m_nDefItem;
    size_t m_nCurrentItem;
};

class CContextMenuView : public CMenuView
{
public:
    CContextMenuView()
    {
        m_ViewType = SCF_CONTEXT_MENU_VIEW;

#ifndef _THICK_FRAME_CONTEXT_MENU
        // Set this flag when scrollbar is not needed.
        m_dwFlags |= CONTENT_VIEW_FLAG_NOSCROLLBAR;
#endif

        /*
        Context menus should always contain Back and Home items that are provided by the device.
        These items should be appended to any context menu that is provided by the gadget.
        In cases where the gadget does not provide a context menu, a menu generated by the device
        containing only Back and Home should be provided. 
        */
        m_pBackViewItem = NULL;
        m_pHomeViewItem = NULL;
    }
    
    virtual ~CContextMenuView() {}

    virtual HRESULT Initialize(CScfContentBase *pScfContentBase);
    virtual HRESULT OnSize(HDC hDC, LONG nClientWidth, LONG nClientHeight);
    virtual HRESULT OnPaint(HDC hdc, int left, int top, int right, int bottom);
    virtual HRESULT OnDeviceEvent(CDevice::DeviceEvent DeviceEvent);

private:
    HRESULT _CreateAndAddViewItem(CScfElement* pBaseElem, CViewMenuItem **ppViewItem);

    CScfDivElement m_DivElem;
    CScfItemElement m_BackItemElem;
    CScfItemElement m_HomeItemElem;
    CViewMenuItem *m_pBackViewItem;     // Will be freed by CContentViewBase destructor
    CViewMenuItem *m_pHomeViewItem;     // Will be freed by CContentViewBase destructor
};
